package ligne2vie.topos.shared.bo;

import java.util.List;

import com.google.gwt.maps.client.geocoder.HasAddressComponent;

/**
 * The class {@link AddressHelper} provides useful methods helping to manage addresses.
 * 
 * @author thuguerre
 * @since 1.1.0
 */
public class AddressHelper {

	/**
	 * The method {@link #getAddressComponent(List, String)} returns the first address component contained in the
	 * received list of components and whose type is the one expected. If no component matches, the method return
	 * <code>null</code>.
	 * 
	 * @param components
	 *            List of address components to parse.
	 * @param type
	 *            Type of the address component to get.
	 * @return First found corresponding address component. <code>null</code> else.
	 * 
	 * @see http://code.google.com/intl/fr-FR/apis/maps/documentation/geocoding/#Types
	 */
	private static HasAddressComponent getAddressComponent(List<HasAddressComponent> components, String type) {

		for (HasAddressComponent component : components) {
			if (component.getTypes().contains(type)) {
				return component;
			}
		}

		return null;
	}

	/**
	 * The method {@link #getFormatedAddressBlock(List, String)} returns a formated block address, using given
	 * separator.
	 * 
	 * @param components
	 *            List of available address components.
	 * @param separator
	 *            Separator to use to separate each address components.
	 * @return Valid String representing a valid blok address.
	 */
	private static String getFormatedAddressBlock(List<HasAddressComponent> components, String separator) {

		HasAddressComponent aal2 = getAddressComponent(components, "administrative_area_level_2");
		HasAddressComponent country = getAddressComponent(components, "country");
		HasAddressComponent establishment = getAddressComponent(components, "establishment");
		HasAddressComponent locality = getAddressComponent(components, "locality");
		HasAddressComponent naturalFeature = getAddressComponent(components, "natural_feature");
		HasAddressComponent pointOfInterest = getAddressComponent(components, "point_of_interest");
		HasAddressComponent postalCode = getAddressComponent(components, "postal_code");
		HasAddressComponent route = getAddressComponent(components, "route");
		HasAddressComponent streetNumber = getAddressComponent(components, "street_number");

		StringBuilder address = new StringBuilder();

		// --- description of the place

		if (naturalFeature != null) {
			address.append(naturalFeature.getLongName()).append(separator);
		}

		if (pointOfInterest != null) {
			address.append(pointOfInterest.getLongName()).append(separator);
		}

		if (establishment != null
				&& ((pointOfInterest != null && !establishment.getLongName().equals(pointOfInterest.getLongName())) || (pointOfInterest == null))) {
			address.append(establishment.getLongName()).append(separator);
		}

		// --- street address : number + street name

		if (route != null) {

			if (streetNumber != null) {
				address.append(streetNumber.getLongName()).append(", ");
			}

			address.append(route.getLongName()).append(separator);
		}

		// --- locality

		if (locality != null
				&& ((aal2 != null && !aal2.getLongName().equals(locality.getLongName()) || (aal2 == null)))) {

			// the previous condition allows preventing displaying twice the same information
			// search example : "pompidou, paris" displays both Paris. Useless.

			address.append(locality.getLongName()).append(separator);
		}

		// --- administrative area + country + zip code

		if (aal2 != null) {
			address.append(aal2.getLongName());

			if (country != null || postalCode != null) {

				address.append(" (");

				if (country != null) {
					address.append(country.getShortName());
				}

				if (country != null && postalCode != null) {
					address.append("-");
				}

				if (postalCode != null) {
					address.append(postalCode.getLongName());
				}

				address.append(")");
			}

			address.append(separator);

		} else {

			if (country != null) {
				address.append(country.getShortName());
			}

			if (country != null && postalCode != null) {
				address.append("-");
			}

			if (postalCode != null) {
				address.append(postalCode.getLongName());
			}
		}

		return address.toString();
	}

	/**
	 * The method {@link #getHtmlFormatedAddressBlock(List)} returns a well structured and directly displayable Html
	 * block address containing all required components.
	 * 
	 * @param components
	 *            List of available address components.
	 * @return Valid Html String.
	 */
	public static String getHtmlFormatedAddressBlock(List<HasAddressComponent> components) {
		return AddressHelper.getFormatedAddressBlock(components, "<br />");
	}
}
